package com.example.java8.feature_06;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class TestCollector {

    public static List<String> boss = Arrays.asList("帝王神龟", "珠圆玉润", "铁爪鬼王", "边疆铁犀", "钢化巨灵");

    public static List<Person> persons = Arrays.asList(
            new Person("帝王神龟", "男", "凤翔古镇", 1000),
            new Person("珠圆玉润", "女", "贵妃寝宫", 800),
            new Person("铁爪鬼王", "男", "皇城", 3600),
            new Person("边疆铁犀", "男", "皇城", 1200),
            new Person("钢化巨灵", "男", "皇城", 400),
            new Person("巨猿", "男", "栖息地", 600)
    );

    public static void main(String[] args){

        testToXxx();
        testJoining();
        testPartitioningBy();
        testGroupBy();
        testSummarizing();
    }


    public static void testToXxx(){
        System.out.println("----------testToXxx-------------------------------------------");
        boss.stream()
                .filter(obj -> obj.contains("王"))           // 过滤包含"王"字的元素
                .collect(Collectors.toList())                // 收集过滤后的元素放在ArrayList集合中返回
                .forEach(obj -> System.out.println(obj));    // 循环输出


        // 返回LinkedList
        LinkedList<String> linkedList = boss.stream().collect(Collectors.toCollection(LinkedList::new));

        // 返回Set
        Set<String> sets = boss.stream().collect(Collectors.toSet());

        // 返回线程安全的集合
        List<String> list = boss.stream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));

        // 返回Map
        Map<String, String> map = boss.stream().collect(Collectors.toMap(String::toString, Function.identity()));
        map.keySet().forEach(key -> System.out.println(map.get(key)));
    }

    public static void testJoining(){
        System.out.println("----------testJoining-------------------------------------------");
        String r1 = boss.stream().collect(Collectors.joining());
        String r2 = boss.stream().collect(Collectors.joining("-"));
        String r3 = boss.stream().collect(Collectors.joining("-", "[", "]"));
        System.out.println(r1);
        System.out.println(r2);
        System.out.println(r3);
    }

    public static void testPartitioningBy(){
        System.out.println("----------testPartitioningBy-------------------------------------------");
        Map<Boolean, List<String>> map = boss.stream().collect(
                // 将流中元素包含"王"字的分为一组,不包含的在另外一组
                Collectors.partitioningBy(obj -> obj.contains("王"))
        );
        System.out.println(map);
    }

    public static void testGroupBy(){
        System.out.println("----------testGroupBy-------------------------------------------");

        // 按性别分组
        System.out.println("--按性别分组---------------------------------");
        Map<String, List<Person>> sexMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getSex));
        sexMap.forEach((key, value) -> {
            System.out.println("--" + key + "--");
            System.out.println(value);
        });

        // 按地址分组
        System.out.println("--按地址分组---------------------------------");
        Map<String, List<Person>> addressMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getAddress));
        addressMap.forEach((key, value) -> {
            System.out.println("--" + key + "--");
            System.out.println(value);
        });

        // 多级分组-先按性别分组、再按地址分组
        System.out.println("--多级分组---------------------------------");
        Map<String, Map<String, List<Person>>> map = persons.stream()
                .collect(Collectors.groupingBy(Person::getSex,
                        Collectors.groupingBy(Person::getAddress)));
        map.forEach((sex, group) -> {
            System.out.println("--" + sex + "--");
            group.forEach((key, value) -> {
                System.out.println("--" + key +"--");
                System.out.println(value);
            });
        });

        // 分组统计
        System.out.println("--分组统计---------------------------------");
        Map<String, Long> countMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getSex, Collectors.counting()));
        countMap.forEach((key, value) -> {
            System.out.println(key + ":" + value);
        });
    }


    public static void testSummarizing(){
        System.out.println("----------testGroupBy-------------------------------------------");

        // 统计收集器
        IntSummaryStatistics statistics = persons.stream().collect(Collectors.summarizingInt(Person::getAge));
        System.out.println("BOSS平均值：" + statistics.getAverage());
        System.out.println("BOSS数：" + statistics.getCount());
        System.out.println("最⼤BOSS：" + statistics.getMax());
        System.out.println("最⼩BOSS：" + statistics.getMin());
        System.out.println("BOSS总和：" + statistics.getSum());

        // 总和收集器
        Long sum = persons.stream().collect(Collectors.summingLong(Person::getAge));
        System.out.println(sum);


        // 平均收集器
        Double avg = persons.stream().collect(Collectors.averagingInt(Person::getAge));
        System.out.println(avg);
    }


    static class Person{
        private String name;

        private String sex;

        private String address;

        private Integer age;

        public Person(String name, String sex, String address, Integer age){
            this.name = name;
            this.sex = sex;
            this.address = address;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

}
